import { ReportData, MonitorOptions } from '../types';
import { getUserId } from '../utils/helper';

export class Reporter {
  private options: Required<MonitorOptions>;
  private queue: Record<string, ReportData[]> = {
    error: [],
    performance: [],
    behavior: []
  };
  private timer: number | null = null; // 批量上报定时器
  private cacheKey = 'monitor_sdk_cache'; // localStorage缓存键

  constructor(options: MonitorOptions) {
    // 合并默认配置
    this.options = {
      batchSize: 10,
      batchInterval: 30000,
      enableError: true,
      enablePerformance: true,
      enableBehavior: true,
      appKey: '',
      beforeReport: (data) => data,
      ...options
    };

    // 初始化时重试缓存的失败数据
    this.retryFailedReports();

    // 监听页面卸载，确保最后一批数据上报
    window.addEventListener('beforeunload', () => this.flush());
  }

  /**
   * 添加数据到队列
   */
  push(data: ReportData) {
    // 执行上报前钩子
    const processedData = this.options.beforeReport?.(data);
    // 关键修改：类型守卫，确保 processedData 是对象
    if (!processedData || typeof processedData !== 'object') return;

    // 补充公共字段（现在扩展运算符不会报错）
    const reportData = {
      ...processedData, // 现在 processedData 是明确的对象类型
      appKey: this.options.appKey,
      userId: getUserId(),
      timestamp: Date.now(),
      url: window.location.href,
      userAgent: navigator.userAgent
    };

    // 按类型加入队列
    if (this.queue[reportData.type]) {
      this.queue[reportData.type].push(reportData);
      this.checkReportCondition(reportData.type);
    }
  }

  /**
   * 检查是否满足上报条件（数量或时间）
   */
  private checkReportCondition(type: string) {
    const queue = this.queue[type];
    // 数量达标立即上报
    if (queue.length >= this.options.batchSize) {
      this.report(type);
      return;
    }
    // 时间达标（设置定时器）
    if (!this.timer) {
      this.timer = window.setTimeout(() => {
        Object.keys(this.queue).forEach(type => {
          if (this.queue[type].length > 0) this.report(type);
        });
        this.timer = null;
      }, this.options.batchInterval);
    }
  }

  /**
   * 执行上报
   */
  private report(type: string) {
    const dataList = this.queue[type];
    if (dataList.length === 0) return;

    // 深拷贝并清空队列
    const reportData = [...dataList];
    this.queue[type] = [];

    // 构造上报体
    const payload = { type, dataList: reportData };

    // 发送请求（优先sendBeacon，降级XMLHttpRequest）
    this.sendRequest(payload)
      .catch(() => this.cacheFailedReport(payload));
  }

  /**
   * 发送请求
   */
  private sendRequest(payload: any): Promise<void> {
    return new Promise((resolve, reject) => {
      const data = JSON.stringify(payload);

      // 1. 优先使用sendBeacon（页面卸载时更可靠）
      if (navigator.sendBeacon) {
        const blob = new Blob([data], { type: 'application/json' });
        const success = navigator.sendBeacon(this.options.reportUrl, blob);
        success ? resolve() : reject(new Error('sendBeacon failed'));
        return;
      }

      // 2. 降级使用XMLHttpRequest
      const xhr = new XMLHttpRequest();
      xhr.open('POST', this.options.reportUrl, true);
      xhr.setRequestHeader('Content-Type', 'application/json');
      xhr.onload = () => {
        if (xhr.status >= 200 && xhr.status < 300) resolve();
        else reject(new Error(`HTTP error: ${xhr.status}`));
      };
      xhr.onerror = () => reject(new Error('Network error'));
      xhr.send(data);
    });
  }

  /**
   * 缓存失败的上报数据
   */
  private cacheFailedReport(payload: any) {
    try {
      const cached = JSON.parse(localStorage.getItem(this.cacheKey) || '[]');
      cached.push({ ...payload, cacheTime: Date.now() });
      // 限制缓存数量（最多100条）
      if (cached.length > 100) cached.splice(0, cached.length - 100);
      localStorage.setItem(this.cacheKey, JSON.stringify(cached));
    } catch (e) {
      console.error('缓存上报数据失败:', e);
    }
  }

  /**
   * 重试缓存的失败数据
   */
  private retryFailedReports() {
    try {
      const cached = JSON.parse(localStorage.getItem(this.cacheKey) || '[]');
      if (cached.length === 0) return;

      // 逐条重试
      cached.forEach((item: any, index: number) => {
        this.sendRequest(item)
          .then(() => {
            cached.splice(index, 1);
            localStorage.setItem(this.cacheKey, JSON.stringify(cached));
          })
          .catch(() => console.log('重试失败，保留缓存'));
      });
    } catch (e) {
      console.error('重试缓存数据失败:', e);
    }
  }

  /**
   * 强制上报所有队列数据（页面卸载时调用）
   */
  flush() {
    Object.keys(this.queue).forEach(type => {
      if (this.queue[type].length > 0) this.report(type);
    });
    if (this.timer) clearTimeout(this.timer);
  }
}